# -*- coding: utf-8 -*-

"""剑指 Offer II 050. 向下的路径节点之和
给定一个二叉树的根节点 root ，和一个整数 targetSum ，求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始，也不需要在叶子节点结束，但是路径方向必须是向下的（只能从父节点到子节点）。

示例 1：
输入：root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出：3
解释：和等于 8 的路径有 3 条，如图所示。

示例 2：
输入：root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出：3

提示:
二叉树的节点个数的范围是 [0,1000]
-10^9 <= Node.val <= 10^9 
-1000 <= targetSum <= 1000 """


# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right


class Solution:
    """可以用前缀和来解决本问题，采用前序遍历方法，深度优先的遍历就是到当前节点的路径，同一时刻只有一条路径，
    同时维护一张哈希字典记录：根节点到当前节点这条路径上的前缀和，每个前缀和值出现的次数。
    一边向下一边计算当前前缀和，通过查表看看符合条件的区间路径条数

    需要注意的是，1.此哈希字典对前缀和的记录应该有进有出，退出某节点时应该对字典表和前缀和做消解处理；
    2.最大节点数为1000，可以用递归实现"""
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        sums, presums_table, total = 0, {0: 1}, 0
        def downward(node):
            nonlocal sums, total
            sums += node.val
            total += presums_table.get(sums-targetSum, 0)
            # print(node.val, sums, total)
            
            if sums in presums_table.keys():
                presums_table[sums] += 1
            else:
                presums_table[sums] = 1
            
            if node.left:
                downward(node.left)
            
            if node.right:
                downward(node.right)
            
            presums_table[sums] -= 1
            sums -= node.val
        
        if root:
            downward(root)
        
        return total


if __name__ == "__main__":
    so = Solution()
    root = TreeNode(5, TreeNode(4, TreeNode(11, TreeNode(7), TreeNode(2))), TreeNode(8, TreeNode(13), TreeNode(4, TreeNode(5, TreeNode(1)))))
    print(so.pathSum(root, 22))

